package com.xqboss.apps.controller.order;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.xqboss.apps.convert.order.OrderConverter;
import com.xqboss.apps.domain.order.OrderMain;
import com.xqboss.apps.domain.param.AesParams;
import com.xqboss.apps.dto.order.*;
import com.xqboss.apps.enums.nft.NftDispatchSourceEnum;
import com.xqboss.apps.enums.order.OrderStatusEnum;
import com.xqboss.apps.enums.order.OrderTypeEnum;
import com.xqboss.apps.enums.order.OutOrderStatusEnum;
import com.xqboss.apps.service.aliyun.SampleService;
import com.xqboss.apps.service.box.BoxService;
import com.xqboss.apps.service.consumer.ConsumerRealNameService;
import com.xqboss.apps.service.order.NftDispatchRecordService;
import com.xqboss.apps.service.order.OrderService;
import com.xqboss.apps.service.order.PayApplyService;
import com.xqboss.apps.service.order.pay.impl.WalletPayExecutor;
import com.xqboss.apps.vo.box.BoxInfoVo;
import com.xqboss.apps.vo.order.AppOrderDetailVo;
import com.xqboss.apps.vo.order.AppOrderItemListVo;
import com.xqboss.apps.vo.order.AppOrderListVo;
import com.xqboss.apps.vo.order.OpenQuickCopyDto;
import com.xqboss.apps.vo.pay.PayInfoVo;
import com.xqboss.apps.vo.user.UserNFTItemVo;
import com.xqboss.common.annotation.RateLimiter;
import com.xqboss.common.annotation.RepeatSubmit;
import com.xqboss.common.constant.HttpStatus;
import com.xqboss.common.core.controller.BaseController;
import com.xqboss.common.core.domain.R;
import com.xqboss.common.enums.LimitType;
import com.xqboss.common.exception.ServiceException;
import com.xqboss.common.utils.ValidatorUtil;
import com.xqboss.common.utils.aes.AesUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotNull;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单控制器
 * </p>
 *
 * @author Trent
 * @date 2023/8/23
 */
@Api(tags = "订单-用户订单管理")
@RestController
@RequestMapping("/user/order")
public class OrderController extends BaseController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private PayApplyService payApplyService;

    @Autowired
    private ConsumerRealNameService realNameService;

    @Autowired
    private OrderConverter orderConverter;

    @Autowired
    private NftDispatchRecordService nftRecordService;

    @Autowired
    private WalletPayExecutor walletPayExecutor;

    @Autowired
    private BoxService boxService;

    @Autowired
    private SampleService sampleService;


    @RepeatSubmit(interval = 1000, justUrl = true, message = "访问过于频繁，请稍后再试")
    @RateLimiter(key="create_box_nft:", time = 5, count = 5, limitType = LimitType.IP)
    @SentinelResource("盒子下单")
    @ApiOperation("NFT盒子下单")
    @PostMapping("create/box-nft")
    public R<AppOrderListVo> boxNftCreate(@Validated @RequestBody CreateBoxNftOrderDto request, HttpServletRequest req) throws Exception {
        //用户行为验证
        Boolean check = sampleService.check(request.getCaptchaVerifyParam(), req);
        //如果为空或者验证失败，返回错误
        if (Objects.isNull(check) || !check) {
            return R.fail(HttpStatus.FIRST_ORDER_FAILED_BOX_NFT, "验证失败，请重新提交订单");
        }
        // 实名认证才能下单
        realNameService.requireRealName(getUserId());
        CreateOrderDto params = new CreateOrderDto();
        params.setOrderType(OrderTypeEnum.Box_NFT);
        params.setToken(request.getToken());
        params.setPrice(request.getPrice());
        params.setQuantity(request.getQuantity());
        params.setSourceId(request.getBoxId());
        OrderMain order = orderService.createOrder(getUserId(), params);
        AppOrderListVo vo = orderConverter.toAppOrderListVo(order);
        return R.ok(vo);
    }

    @RepeatSubmit(interval = 1000, justUrl = true, message = "访问过于频繁，请稍后再试")
    @SentinelResource("市场下单")
    @ApiOperation("市场下单")
    @PostMapping("create/market")
    public R<AppOrderListVo> marketCreate(@Validated @RequestBody CreateMarketOrderDto request) {
        // 实名认证才能下单
        realNameService.requireRealName(getUserId());
        request.setPrice(request.getPrice().setScale(2, RoundingMode.HALF_UP));
        // 下单
        CreateOrderDto params = new CreateOrderDto();
        if (request.getGiftUserId() != null) {
            params.setOrderType(OrderTypeEnum.Gift);
        } else {
            params.setOrderType(OrderTypeEnum.Market);
        }
        params.setToken(request.getToken());
        params.setPrice(request.getPrice());
        params.setQuantity(request.getQuantity());
        params.setSourceId(request.getMarketId());
        params.setGiftUserId(request.getGiftUserId());
        OrderMain order = orderService.createOrder(getUserId(), params);
        AppOrderListVo vo = orderConverter.toAppOrderListVo(order);
        return R.ok(vo);
    }

    @ApiOperation(value = "检测是否有订单待支付")
    @GetMapping("get-unpay-order")
    public R<AppOrderListVo> getUnpayOrder(@Validated GetUnpayOrderDto request) {
        // 判断是否已经有同类未支付订单商品，如果有则返回订单信息，
        WebOrderListDto queryWaitPayOrder = new WebOrderListDto();
        queryWaitPayOrder.setOrderType(request.getOrderType());
        queryWaitPayOrder.setMarketType(request.getMarketType());
        queryWaitPayOrder.setOrderStatus(OutOrderStatusEnum.UN_PAY);
        queryWaitPayOrder.setPageNum(1);
        queryWaitPayOrder.setPageSize(1);
        queryWaitPayOrder.setOrderByColumn("id");
        queryWaitPayOrder.setBuyerId(getUserId());
        queryWaitPayOrder.setSortAsc(false);
        List<OrderMain> orderList = orderService.getOrderList(queryWaitPayOrder);
        AppOrderListVo vo = null;
        if (!orderList.isEmpty()) {
            vo = orderConverter.toAppOrderListVo(orderList.get(0));
        }
        return R.ok(vo);
    }

    @ApiOperation("同步订单支付状态并获取详情")
    @PostMapping("sync-status")
    public R<AppOrderDetailVo> syncOrderStatus(@Validated @RequestBody SyncStatusDto dto) {
        orderService.syncOrderPayStatus(dto.getOrderId(), getUserId());

        OrderMain orderDetail = orderService.getOrderDetail(dto.getOrderId(), getUserId());
        if (orderDetail.getStatus() != OrderStatusEnum.COMPLETED && orderDetail.getStatus() != OrderStatusEnum.PAYED) {
            throw new ServiceException("订单未支付！");
        }
        List<UserNFTItemVo> nftItemList;
        if (orderDetail.getOrderType() == OrderTypeEnum.Market || orderDetail.getOrderType() == OrderTypeEnum.Gift) {
            nftItemList = nftRecordService.getRecordByOrderId(NftDispatchSourceEnum.MARKET, orderDetail.getId());
        }
        else {
            nftItemList = nftRecordService.getRecordByOrderId(NftDispatchSourceEnum.ORDER, orderDetail.getId());
        }
        AppOrderDetailVo vo = orderConverter.toAppOrderDetailVo(orderDetail, nftItemList);
        return R.ok(vo);
    }

    @RepeatSubmit(interval = 500, justUrl = true)
    @ApiOperation("订单申请支付")
    @PostMapping("pay-apply")
    public R<PayInfoVo> payApply(@Validated @RequestBody PayApplyDto request) {
        PayInfoVo payInfoVo = payApplyService.applyPay(request.getOrderId(), getUserId(), request.getPayType());
        return R.ok(payInfoVo);
    }

    @RepeatSubmit(interval = 500, justUrl = true)
    @ApiOperation("钱包支付校验")
    @PostMapping("wallet-pay")
    public R walletPay(HttpServletRequest request, @Validated @RequestBody AesParams param) {
        WalletPayDto params = AesUtil.decryptToObject(param.getParamStr(), WalletPayDto.class);
        ValidatorUtil.valid(params);
        TradeResultDto resultDto = walletPayExecutor.verifyCallback(request, params);
        payApplyService.paySuccess(resultDto);
        return R.ok();
    }

    @ApiOperation("获取订单列表")
    @GetMapping("list")
    public R<List<AppOrderListVo>> list(@Validated WebOrderListDto params) {
        params.setBuyerId(getUserId());
        List<OrderMain> orderList = orderService.getOrderList(params);
        List<AppOrderListVo> voList = orderConverter.toAppOrderListVoList(orderList);
        return R.ok(voList, orderList);
    }


    @ApiOperation("获取订单详情")
    @GetMapping("detail/{orderId}")
    public R<AppOrderDetailVo> detail(@Validated @PathVariable("orderId")
                                      @ApiParam(value = "订单号", required = true)
                                      @NotNull(message = "订单号不能为空")
                                      Long orderId) {
        OrderMain orderDetail = orderService.getOrderDetail(orderId, getUserId());
        List<UserNFTItemVo> nftItemList;
        if (orderDetail.getOrderType() == OrderTypeEnum.Market) {
            nftItemList = nftRecordService.getRecordByOrderId(NftDispatchSourceEnum.MARKET, orderDetail.getId());
        } else {
            nftItemList = nftRecordService.getRecordByOrderId(NftDispatchSourceEnum.ORDER, orderDetail.getId());
        }
        // 需要清除装备信息
        nftItemList = nftItemList.stream().peek(nft -> nft.setEquipment(null)).collect(Collectors.toList());

        AppOrderDetailVo vo = orderConverter.toAppOrderDetailVo(orderDetail, nftItemList);
        // 如果是盒子订单，则获取盒子的发行方
        if (vo.getOrderType() == OrderTypeEnum.Box_NFT) {
            if (vo.getOrderItems() != null) {
                for (AppOrderItemListVo orderItem : vo.getOrderItems()) {
                    // 获取箱子的一级二级分类信息
                    BoxInfoVo categoryInfo = boxService.getCategoryInfo(orderItem.getSpuId());
                    if (categoryInfo != null) {
                        orderItem.setPcName(categoryInfo.getPcName());
                        orderItem.setCategoryName(categoryInfo.getCategoryName());
                    }
                }
            }
        }
        return R.ok(vo);
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @ApiOperation("用户取消订单")
    @GetMapping("cancel/{orderId}")
    public R cancel(@Validated @PathVariable("orderId")
                    @ApiParam(value = "订单号", required = true)
                    @NotNull(message = "订单号不能为空")
                    Long orderId) {
        orderService.cancel(orderId, getUserId());
        return R.ok();
    }

    @RepeatSubmit(interval = 1000, justUrl = true)
    @ApiOperation("开启快速抄货")
    @PostMapping("openQuickCopy")
    public R<String> openQuickCopy(@Validated @RequestBody AesParams param) {
        Long userId = getUserId();
        // 解密
        OpenQuickCopyDto dto = AesUtil.decryptToObject(param.getParamStr(), OpenQuickCopyDto.class);
        String token = orderService.openQuickCopy(dto, userId);
        return R.ok(token, "已开启快速抄货");
    }

    /**
     * 快速抄货支付
     *
     * @return
     */
    @RepeatSubmit(interval = 1000, justUrl = true, message = "访问过于频繁，请稍后再试")
    @ApiOperation("快速抄货购买")
    @PostMapping("quickCopyPay")
    public R quickCopyPay(@Validated @RequestBody QuickCopyDto dto,HttpServletRequest request) {
        // create/market
        // pay-apply
        // wallet-pay
        // sync-status
        Long userId = getUserId();
        realNameService.requireRealName(userId);
        return orderService.quickCopyPay(dto, userId, request);
    }
}